#include "mem_alloc.h"
#include <stdlib.h>

#define PAGE_SIZE 4096 
#define DEFAULT_ALIGN 16

#define ROUNDUP(a) \
    ((a) + DEFAULT_ALIGN - 1) & (~(DEFAULT_ALIGN -1))

#define INDEXOF(a) \
    (((a) + DEFAULT_ALIGN - 1) / DEFAULT_ALIGN - 1)

typedef struct list_node {
    struct list_node * next;
    void * data;
} list_node;

#define MAX_SLOT INDEXOF(PAGE_SIZE) + 1

static list_node * malloc_array[MAX_SLOT] = {0};
static unsigned int malloc_static[MAX_SLOT];

static unsigned int mem_alloc_size = 0;
static unsigned int mem_free_size = 0;

list_node * mem_malloc_from_sys(unsigned int n)
{
    int i, index;
    char * mem;
    int cnt;
	list_node * head;

    n = ROUNDUP(n);


    mem = (char*)malloc(PAGE_SIZE);
    if (mem == 0) {
        return 0;
    }

    mem_alloc_size += PAGE_SIZE;
    mem_free_size += PAGE_SIZE;

    index = INDEXOF(n);

    malloc_static[index] += PAGE_SIZE;

    cnt = PAGE_SIZE / n;

    head = 0;
    for (i = 0; i < cnt; i++) {
        list_node * p = (list_node*)mem;
        p->next = head;
        head = p;
        mem += n;
    }
    return head;
}

void * get_mem(size_t n)
{
    int index;
    list_node * p;


#ifdef _DEBUG
    void * xp = malloc(n);
    return xp;
#endif

    if (n == 0) {
        return 0;
    }

    index = INDEXOF(n);
    if (index >= MAX_SLOT) {
        mem_alloc_size += n;
        return malloc(n);
    }

    n = ROUNDUP(n);
    if (malloc_array[index] == 0) {
        malloc_array[index] = mem_malloc_from_sys(n);
    }

    p = malloc_array[index];
    if (p) {
        malloc_array[index] = p->next;

        mem_free_size -= n;
        malloc_static[index] -= n;
    }
    return p;
}

void release_mem(void * p, size_t n)
{
    int index;
    list_node * node;

#ifdef _DEBUG
    free(p);
	return;
#endif

    if (!p) {
        return;
    }

    index = INDEXOF(n);
    if (index >= 256) {
        mem_alloc_size -= n;
        free(p);
		return;
    }

    node  = (list_node*)p;
    node->next = malloc_array[index];
    malloc_array[index] = node;

    mem_free_size += n;
    malloc_static[index] += n;
}

void mem_save_exit()
{
}
